package cn.com.cfae.iras.doc.analyze.parse.extractor;

import cn.com.cfae.iras.doc.analyze.parse.kv.KVText;
import cn.com.cfae.iras.doc.analyze.parse.kv.TextLayout;
import cn.com.cfae.iras.doc.analyze.parse.model.*;
import cn.com.cfae.iras.doc.analyze.parse.tokenizer.DWDBTokenizer;
import cn.com.cfae.iras.doc.analyze.parse.tokenizer.FXJGTokenizer;
import cn.com.cfae.iras.doc.analyze.parse.tokenizer.ZCFZTokenizer;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

/**
 * 债务融资工具信用增进
 */
public class M8Extractor extends MTableExtractor {
    private static final Logger logger = LoggerFactory.getLogger(M8Extractor.class);

    private ZCFZTokenizer zcfzTokenizer = ZCFZTokenizer.getInstance();
    private DWDBTokenizer dwdbTokenizer = DWDBTokenizer.getInstance();
    private FXJGTokenizer fxjgTokenizer = FXJGTokenizer.getInstance();

    @Override
    public void extract() {
        try {
            extractM8();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    private void extractM8() {
        try {
            parseChapterSection();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        try {
            extractM8Xyzjjg();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        try {
            extractM8Dwdbje();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        try {
            extractM8Zcfz();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 净资产、所有者权益
     */
    private void extractM8Zcfz() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取：{}章资产负债表业务模型......", getChapterModel().getChapterId());
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("ZCFZ");
        zcfzTokenizer.loadCoreSynonyms(extractBizModel);
        List<PageModel> pageModelList = getChapterModel().getPageModelList();
        PageModel pageModel = null;
        List<YearIndex> yearIndexList = new ArrayList<>();
        int startPage = 0;
        int offset = 0;
        int thresholdValue = 3;
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            List<String> tableDataList = pageModel.getTableDataList();
            if (tableDataList == null || tableDataList.isEmpty()) {
                continue;
            }
            if (yearIndexList.size() >= thresholdValue) {
                break;
            }
            for (int j = 0; j < tableDataList.size(); j++) {
                String tableDataString = tableDataList.get(j);
                JsonElement tableDataJsonElement = str2Json(tableDataString);
                JsonObject tableData = tableDataJsonElement.getAsJsonArray().get(0).getAsJsonObject();
                JsonArray dataArray = tableData.get("data").getAsJsonArray();
                if (yearIndexList.size() >= thresholdValue) {
                    break;
                }
                for (int k = 0; k < dataArray.size(); k++) {
                    JsonArray itemArray = dataArray.get(k).getAsJsonArray();
//                    if (dataArray.size() <= 3) {
//                        logger.warn("抽取：{}章资产负债表业务模型，表格列数大小有误，跳过！！！");
//                        continue;
//                    }
                    for (int l = 0; l < itemArray.size(); l++) {
                        JsonObject cell = itemArray.get(l).getAsJsonObject();
                        String text = cell.get("text").getAsString();
                        String year = null;
                        if (isEmpty(text)) {
                            continue;
                        }
                        text = replaceCRLF(text).trim();
                        if (isZCFZ_NB(text)) {
                            year = extractZCFZ_NB(text);//年报
                            extractBizModel.addTable(year);
                            logger.info("抽取{}章合并财务报表，报表类型：{}，分析抽取财报年份：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), year);
                        } else if (isZCFZ_JB(text)) {//季报
                            year = extractZCFZ_JB(text);
                            extractBizModel.addTable(year);
                            logger.info("抽取{}章合并财务报表，报表类型：{}，分析抽取财报年份：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), year);
                        } else {
                            logger.info("抽取{}章合并财务报表，报表类型：{}，未知数据：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), text);
                        }
                        if (!isEmpty(year)) {
                            yearIndexList.add(new YearIndex(l, year));
                        }
                    }
                    if (yearIndexList.size() >= thresholdValue) {
                        offset = i;
                        startPage = pageModel.getPageNumber();
                        break;
                    }
                }
            }

        }
        if (yearIndexList.isEmpty()) {
            return;
        }
        List<String> tableDataList = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            tableDataList.addAll(pageModelList.get(i + offset).getTableDataList());
        }
        if (tableDataList.isEmpty()) {
            return;
        }
        ExtractItem extractItem = null;
        logger.info("抽取{}章合并财务报表，报表类型：{}，定位表格位置，提取表格内容已完成，开始提取财报数据......", getChapterModel().getChapterId(), extractBizModel.getModelName());
        for (int i = 0; i < tableDataList.size(); i++) {
            String tableData = tableDataList.get(i);
            int pageNum = i + startPage;
            logger.info("抽取{}章合并财务报表，报表类型：{}，第{}页，数据：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), (startPage + i), tableData);
            JsonArray pageData = str2Json(tableData).getAsJsonArray();
            JsonObject var1 = pageData.get(0).getAsJsonObject();
            JsonArray var2 = var1.get("data").getAsJsonArray();
            //TODO offset后续还需动态调整，有的报表可能跨2行
            clearEmptyCell(var2, yearIndexList.size() + 1, 1);
            for (int j = 0; j < var2.size(); j++) {
                JsonArray var3 = var2.get(j).getAsJsonArray();
                if (var3.size() < yearIndexList.size() + 1) {
                    continue;
                }
                JsonElement textElement = var3.get(0).getAsJsonObject();
                String itemName = replaceCRLF(((JsonObject) textElement).get("text").getAsString());
                logger.info("抽取{}章合并财务报表，报表类型：{}，第{}页，第{}条数据，内容：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), pageNum, j, var3.toString());
                extractItem = extractBizModel.getExtractItemBySynonym(itemName);
                if (extractItem == null) {
                    logger.error("抽取{}章合并财务报表，报表类型：{}，会计科目名称：{}，未能从会计科目列表获取到对应会计科目，继续通过相似度分析......", getChapterModel().getChapterId(), extractBizModel.getModelName(), itemName);
                    for (String synonym : extractBizModel.getSynonyms()) {
                        double similarity = getSimilarAnalyser().similarity(synonym, itemName);
                        if (similarity > 0.9) {
                            extractItem = extractBizModel.getExtractItemBySynonym(synonym);
                            break;
                        }
                    }
                }
                if (extractItem == null) {
                    extractItem = zcfzTokenizer.splitWords3(extractBizModel, itemName);
                    logger.error("抽取{}章合并财务报表，报表类型：{}，经过语义相似度、词库精准匹配分析，还是未能获取到会计科目，通过切词提取......", getChapterModel().getChapterId(), extractBizModel.getModelName());
                    if (extractItem == null) {
                        logger.error("抽取{}章合并财务报表，报表类型：{}，经过语义相似度、词库精准匹配分析，切词分析，还是未能获取到会计科目，中断后续操作！！！", getChapterModel().getChapterId(), extractBizModel.getModelName());
                        continue;
                    }
                }
                logger.info("抽取{}章合并财务报表，报表类型：{}，分析到会计科目名称：{}，数据内容：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), itemName, var3.toString());
                for (int k = 0; k < yearIndexList.size(); k++) {
                    YearIndex yearIndex = yearIndexList.get(k);
                    int index = yearIndex.getIndex();
                    String year = yearIndex.getYear();
                    try {
                        JsonElement amtElement = var3.get(index);
                        ExtractItem newExtractItem = (ExtractItem) BeanUtils.cloneBean(extractItem);
                        newExtractItem.setUnit(extractBizModel.getUnitType());
                        setKV(newExtractItem, textElement, amtElement);
                        newExtractItem.getKey().setPageNumber(pageNum);
                        if (extractBizModel.getTable(year) == null) {
                            extractBizModel.addTable(year);
                        }
                        if (!extractBizModel.getTable(year).containsKey(extractItem.getItemName())) {
                            extractBizModel.getTable(year).put(newExtractItem.getItemName(), newExtractItem);
                        }
                    } catch (IllegalAccessException e) {
                        logger.error(e.getMessage(), e);
                    } catch (InstantiationException e) {
                        logger.error(e.getMessage(), e);
                    } catch (InvocationTargetException e) {
                        logger.error(e.getMessage(), e);
                    } catch (NoSuchMethodException e) {
                        logger.error(e.getMessage(), e);
                    }
                }
                continue;
            }
        }
        zcfzTokenizer.unloadCoreSynonyms(extractBizModel);
        logger.info("抽取{}章资产负债表业务模型，表数据结构：{}。", getChapterModel().getChapterId(), obj2Json(extractBizModel));
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章资产负债表业务模型，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }


    /**
     * 对外担保金额
     */
    private void extractM8Dwdbje() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章对外担保金额业务模型......", getChapterModel().getChapterId());
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("DWDB");
        dwdbTokenizer.loadCoreSynonyms(extractBizModel);
        List<SectionModel> sectionModelList = getChapterModel().getSectionModelList();
        if (CollectionUtils.isEmpty(sectionModelList)) {
            logger.error("抽取{}章对外担保金额业务模型，分析内容为空，请确认！！！", getChapterModel().getChapterId());
            return;
        }
        for (int i = 0; i < sectionModelList.size(); i++) {
            SectionModel sectionModel = sectionModelList.get(i);
            List<SectionModel> childSectionModelList = sectionModel.getChildSectionModelList();
            if (CollectionUtils.isEmpty(childSectionModelList)) {
                continue;
            }
            for (int j = 0; j < childSectionModelList.size(); j++) {
                SectionModel childSectionModel = childSectionModelList.get(j);
                String content = childSectionModel.getContent();
                if (isEmpty(content)) {
                    continue;
                }
                logger.info("抽取{}章业对外担保金额业务模型，指标名称：{}，分析文本：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), childSectionModel.getTitle());
                dwdbTokenizer.splitWords6(extractBizModel, childSectionModel);
                ExtractItem extractItem = extractBizModel.getExtractItem("DWDBJE");
                if (extractItem.getKey() != null && extractItem.getValue() != null) {
                    break;
                }
            }
        }
        dwdbTokenizer.unloadCoreSynonyms(extractBizModel);
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章对外担保金额业务模型完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }

    private void extractM8Xyzjjg() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取：{}章业务模型数据......", getChapterModel().getChapterId());
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("XYZJJG");
        fxjgTokenizer.loadCoreSynonyms(extractBizModel);
        ExtractItem extractItem = null;
        List<PageModel> pageModelList = getPageModelList();
        PageModel pageModel;
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            JsonArray itemArray = getPageDataArray(pageModel);
            for (int j = 0; j < itemArray.size(); j++) {
                JsonArray items = itemArray.get(j).getAsJsonArray();
                String combineLine = combineTextJsonArray(items);
                if (isEmpty(combineLine)) {
                    continue;
                }
                extractItem = fxjgTokenizer.splitWords(extractBizModel, combineLine);
                if (extractItem == null) {
                    continue;
                }
                if (XYZJJGModel.MC.equalsIgnoreCase(extractItem.getItemName())) {
                    if (isFXJG_SPLIT_Format(combineLine)) {
                        String splitChar = findFXJG_Format_Split_Char(combineLine);
                        String[] splits = combineLine.split(splitChar);
                        if (splits.length == 2) {
                            String key = splits[0];
                            String value = splits[1];
                            KVText kText = new KVText();
                            kText.setText(key);
                            kText.add(createKVTextLayout(pageModel, items.get(0).getAsJsonObject()));
                            KVText vText = new KVText();
                            vText.setText(value);
                            vText.add(createKVTextLayout(pageModel, items.get(0).getAsJsonObject()));
                            vText.getTextLayout().setText(vText.getText());
                            extractItem.setKey(kText);
                            extractItem.setValue(vText);
                            kText.setPageNumber(pageModel.getPageNumber());
                            vText.setPageNumber(pageModel.getPageNumber());
                        }
                    }
                    break;
                }
            }
            if (extractItem != null) {
                break;
            }
        }
        fxjgTokenizer.unloadCoreSynonyms(extractBizModel);
        long t2 = System.currentTimeMillis();
        logger.info("抽取：{}章业务模型数据完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }
}
